<?php
/**
 * @link https://www.kancloud.cn/cleverstone/ymb2
 * @copyright Copyright (c) 2020 Yii Manager Software LLC
 */

namespace backend\controllers;

use builder\base\BaseController;
use builder\form\FormBuilder;
use builder\helper\App;
use builder\helper\H5;
use builder\helper\Str;
use builder\helper\T;
use builder\helper\Url;
use builder\widget\ajax\MediaList;
use common\models\Admin;
use common\models\AdminService;
use common\models\SystemGroup;
use common\models\SystemGroupService;
use extend\Extend;
use yii\helpers\Json;

/**
 * 管理员
 * @author clevstn
 * @since ym2.0
 */
class AdminController extends BaseController
{
    public $actionVerbs = [
        'index' => ['GET'],
        'create' => ['GET', 'POST'],
        'update' => ['GET', 'POST'],
        'delete' => ['POST'],
        'detail' => ['GET'],
    ];

    /**
     * 列表
     * @return string
     * @throws \builder\base\InvalidInstanceException
     * @throws \builder\base\NotFoundParamsException
     */
    public function actionIndex()
    {
        $viewBuilder = $this->viewBuilder;
        $table = $viewBuilder->table->setId('Admin_Index');
        if ($this->isAjax) {
            $table->setQuery(function () {
                $params = $this->filteredGet;
                [$startAt, $endAt] = T::rangeDateSplit($params['created_at'] ?? null);
                $kwdFilter = [];
                if (!empty($params['keyword'])) {
                    $kwd = $params['keyword'];
                    if (preg_match(PHP_MOBILE_REGEX, $kwd)) {
                        //手机号
                        $kwdFilter = ['mobile' => $kwd];
                    } elseif (preg_match(PHP_EMAIL_REGEX, $kwd)) {
                        //邮箱
                        $kwdFilter = ['email' => $kwd];
                    } else {
                        //账号
                        $kwdFilter = ['username' => $kwd];
                    }
                }

                $query = Admin::query();
                $query->andFilterWhere([
                    'and',
                    $kwdFilter,
                    ['status' => $params['status'] ?? null],
                    ['group' => $params['group'] ?? null],
                    ['between', 'created_at', $startAt, $endAt],
                ]);

                return $query;
            })
                ->setColumnDependency(function () {
                    return SystemGroupService::getAllGroupColumns();
                })
                ->setOrderBy(['created_at' => SORT_DESC])
                ->setColumns([
                    'id',
                    'Photo_Str' => function ($row) {
                        $avatar = $row['photo'] ?: Url::getBackendDefaultAvatar(false);
                        return H5::imgX($avatar, 30, 30);
                    },
                    'username',
                    'Email_Str' => function ($row) {
                        return $row['email'] ? Str::overflowMiddleEllipsis($row['email'], 10, '******') : '-';
                    },
                    'Mobile_Str' => function ($row) {
                        return $row['mobile'] ? Str::overflowMiddleEllipsis($row['mobile'], 8) : '-';
                    },
                    'Status_Str' => function ($row) {
                        return H5::badgeDot($row['status'] ? '正常' : '封停', $row['status'] ? 'success' : 'red');
                    },
                    'Deny_End_Time_Str' => function ($row) {
                        return $row['deny_end_time'] ?: '-';
                    },
                    'Group_Name' => function ($row, $dependency) {
                        return $dependency[$row['group']];
                    },
                    'created_at',
                    'updated_at',
                    // 操作项
                    'op_admin_delete' => function ($row) {
                        return $row['group'] != Admin::ADMIN_GROUP;
                    },
                ]);
        } else {
            $t = date('t');
            App::setViewBreadcrumb([
                ['name' => '系统管理'],
                ['name' => '管理员列表', 'url' => 'admin/index'],
            ]);

            $table->setTitle('管理员列表')
                ->setRootLayout(['attribute' => ['ym2-image-group' => '']])
                ->setTableHead([
                    $this->tableHead->field('id')->title('ID'),
                    $this->tableHead->field('Photo_Str')->title('头像'),
                    $this->tableHead->field('username')->title('账号'),
                    $this->tableHead->field('Email_Str')->title('邮箱')->minWidth(150),
                    $this->tableHead->field('Mobile_Str')->title('手机号')->minWidth(105),
                    $this->tableHead->field('Status_Str')->title('当前状态'),
                    $this->tableHead->field('Deny_End_Time_Str')->title('封停截止')->minWidth(150),
                    $this->tableHead->field('Group_Name')->title('管理组'),
                    $this->tableHead->field('created_at')->title('注册日期')->minWidth(150),
                    $this->tableHead->field('updated_at')->title('上次更新')->minWidth(150),
                    $this->tableHead->toolbar()->title('操作项')->fixedNone()->width(170),
                ])
                ->setRowOperation([
                    $this->rowOperation->modal('管理员详情')->title('查 看')->route('admin/detail')->closeBtn()->width(945)->height(665),
                    $this->rowOperation->modal('编辑管理员')->title('编 辑')->route('admin/update')->width(920)->height(620),
                    $this->rowOperation->ajax()->title('<span class="text-danger">删 除</span>')->questionDescription('确定要删除此管理员吗？')->route('admin/delete')->method('post')->id('op_admin_delete'),
                ])
                ->setToolbarCustom([
                    $this->toolbarCustom->modal('新增管理员')->btnClass('btn-primary')->title('新 增')->route('admin/create')->width(920)->height(620),
                ])
                ->setToolbarRefresh()
                ->setToolbarFilter([
                    'created_at' => $this->toolbarFilter->datetime()->label('注册日期')->placeholder('请选择')->uiClass('w-auto float-none')->style('width:280px;')->quickChoice(['昨日' => T::createRangeDate('-1 day', '-1 day'), '近3日' => T::createRangeDate('-2 days'), '近7日' => T::createRangeDate('-6 days'), '近'.$t.'日' => T::createRangeDate('-'.($t-1).' days')]),
                    'keyword' => $this->toolbarFilter->text()->label('关键词')->placeholder('请输入账号/邮箱/手机号')->uiClass('w-md-300'),
                    'group' => $this->toolbarFilter->select()->label('管理组')->options(SystemGroupService::getAllGroupColumns())->placeholder('请选择管理组')->uiClass('w-md-300'),
                    'status' => $this->toolbarFilter->select()->label('当前状态')->placeholder('请选择')->options(['封停/锁定', '正常'])->uiConfig('minimumResultsForSearch', -1)->uiClass('w-md-300'),
                ]);
        }

        return $viewBuilder->render();
    }

    /**
     * 新增
     * @return \yii\web\Response|string
     * @throws \Exception
     */
    public function actionCreate()
    {
        if ($this->isPost) {
            $bodyParams = $this->filteredPost;
            // 头像
            $bodyParams['photo'] = App::getFileLinkFromParams($bodyParams, 'photo');

            $user = new Admin();
            $user->setScenario('SCE_Admin_Create');
            $user->load($bodyParams);
            $user->path = '-0-';
            if (!$user->validate()) {
                return $this->asFail($user->error);
            }

            // 禁止添加超级管理员账号
            if ($user->group == Admin::ADMIN_GROUP) {
                return $this->asFail('禁止添加超管账号。#' . $user->username);
            }

            // 禁用或未授权管理组禁止分配
            $systemGroup = SystemGroup::findOne($user->group);
            if (empty($systemGroup)) return $this->asFail('管理组【' . $user->group . '】不存在。');
            if (!$systemGroup->isAllowCreateChild()) return $this->asFail('管理组【' . $user->group . '】禁止分配。');

            // 设置安全属性
            $user->setPassword($user->password_hash);
            $user->invite_code = AdminService::generateInviteCode();
            $user->google_key = Extend::googleAuth()->createSecret();
            $user->setAuthKey();
            $user->sso_key = AdminService::generateSSOKEY();
            $user->access_token = AdminService::generateAccessToken();

            $user->save(false);
            return $this->asOk('添加账号【'. $user->username .'】成功。');
        } else {
            $rowData = SystemGroup::queryOneWithLimit(['>', 'id', 0]);
            if (empty($rowData)) return $this->renderContentX(H5::alert('温馨提示：请添加【管理组】后尝试操作。', 'info', false, ['class' => ['m-3']]));

            return FormBuilder::instance(['id' => 'admin_create'])
                ->setTitle('新增')
                ->setPartial()
                ->setFormControl([
                    'photo' => $this->formControl->file()->label('头像')->max(1)->scenarioImage(),
                    'username' => $this->formControl->text()->label('账号')->required()->maxLength(20)->help('账号只能包含数字、字母、汉字。')->placeholder('请填写账号')->layout(6),
                    'password_hash' => $this->formControl->password()->label('密码')->required()->placeholder('请填写密码')->help("注意：\n1、密码最小长度8位！\n2、密码最大长度20位！\n3、密码必须包含英文字母、数字、特殊字符中的两种。")->layout(6),
                    'password_hash_repeat' => $this->formControl->password()->label('确认密码')->required()->placeholder('请重复密码')->layout(6),
                    'email' => $this->formControl->text()->label('邮箱')->placeholder('请填写邮箱')->checkRule(JS_EMAIL_REGEX)->required()->layout(6),
                    'mobile' => $this->formControl->text()->label('手机号')->checkRule(JS_MOBILE_REGEX)->maxLength(11)->placeholder('请填写手机号')->required()->layout(6),
                    'group' => $this->formControl->xselectTree()->label('管理组')->tips('请选择管理组')->radio()->strict(false)->filterable()->clickClose()->expandedKeys(true)->required()->data(SystemGroupService::tree([], true))->prop(['value' => 'id'])->layout(6),
                ])
                ->setResetBtn('清 空')
                ->setSubmitBtn()
                ->setSubmittedCalls(['parent' => ['Admin_Index']])
                ->setAutoClose()
                ->render();
        }
    }

    /**
     * 编辑
     * @param int $id 管理员ID
     * @return \yii\web\Response|string
     * @throws \Throwable
     * @throws \yii\base\InvalidConfigException
     */
    public function actionUpdate($id)
    {
        $user = Admin::findIdentity($id);
        if ($this->isPost) {
            if (empty($user)) return $this->asFail('账号ID【' . $id . '】错误数据不存在。');

            // 头像路径
            $bodyParams = $this->filteredPost;
            $bodyParams['photo'] = !empty($bodyParams['photo']) ? App::getFileLinkFromParams($bodyParams, 'photo') : '';

            // 超级管理员
            if ($user->group == Admin::ADMIN_GROUP) {
                unset($bodyParams['group'], $bodyParams['status'], $bodyParams['deny_end_time']);
            }

            // 删除账号禁用时间
            if (@$bodyParams['status'] && !empty($bodyParams['deny_end_time'])) {
                $bodyParams['deny_end_time'] = null;
            }

            // 标记账号密码
            $oldPassword = $user->password_hash;
            $user->password_hash = '';

            // 标记账号管理组
            $oldGroup = $user->group;

            $user->setScenario('SCE_Admin_Update');
            $user->load($bodyParams);
            if (!$user->validate()) return $this->asFail($user->error);

            // 处理管理组变更
            if ($user->group != $oldGroup && $user->group != Admin::ADMIN_GROUP) {
                $systemGroup = SystemGroup::findOne($user->group);
                if (empty($systemGroup)) return $this->asFail('管理组【' . $user->group . '】不存在。');
                if (!$systemGroup->isAllowCreateChild()) return $this->asFail('管理组【' . $systemGroup->id . '】未授权或已禁用#' . $id);
            }

            // 处理密码变更
            if ($user->password_hash) {
                $user->setPassword($user->password_hash);
            } else {
                $user->password_hash = $oldPassword;
            }

            $user->save(false);

            return $this->asOk('管理员账号【' . $user->username . '】编辑成功。');
        } else {
            if (empty($user)) {
                return $this->renderContentX(H5::alert('ID【' . $id . '】错误数据不存在', 'error'));
            }

            $formControl = [
                'photo' => $this->formControl->file()->label('头像')->max(1)->scenarioImage()->defaultValue($user->photo),
                'username' => $this->formControl->text()->label('账号')->help('账号只能包含数字、字母、汉字。')->required()->placeholder('请填写账号')->defaultValue($user->username)->layout(6),
                'password_hash' => $this->formControl->password()->label('密码')->placeholder('请填写密码')->help("注意：\n1、密码最小长度8位！\n2、密码最大长度20位！\n3、密码必须包含英文字母、数字、特殊字符中的两种。")->layout(6),
                'password_hash_repeat' => $this->formControl->password()->label('确认密码')->placeholder('请重复密码')->layout(6),
                'email' => $this->formControl->text()->label('邮箱')->placeholder('请填写邮箱')->checkRule(JS_EMAIL_REGEX)->required()->defaultValue($user->email)->layout(6),
                'mobile' => $this->formControl->text()->label('手机号')->checkRule(JS_MOBILE_REGEX)->maxLength(11)->placeholder('请填写手机号')->required()->defaultValue($user->mobile)->layout(6),
                'status' => $this->formControl->radio()->label('状态')->defaultValue($user->status)->options(['封停/锁定', '正常'])->layout(6),
                'trigger' => $this->formControl->trigger()->when('default', 'status', '==', 0)->triggerItems(['deny_end_time' => $this->formControl->datetime()->label('锁定时间')->placeholder('请选择')->defaultValue($user->deny_end_time)])->display(),
                'group' => $this->formControl->xselectTree()->label('管理组')->tips('请选择')->radio()->strict(false)->filterable()->clickClose()->expandedKeys(true)->required()->defaultValue($user->group)->data(SystemGroupService::tree([], true))->prop(['value' => 'id'])->layout(6),
            ];
            if ($user->group == Admin::ADMIN_GROUP) unset($formControl['group'], $formControl['status'], $formControl['trigger']);

            return FormBuilder::instance()
                ->setPartial()
                ->setTitle('编辑')
                ->setFormControl($formControl)
                ->setResetBtn()
                ->setSubmitBtn()
                ->setSubmittedCalls(['parent' => ['Admin_Index']])
                ->setAutoClose()
                ->render();
        }
    }

    /**
     * 删除
     * @return \yii\web\Response
     * @throws \Throwable
     * @throws \yii\db\StaleObjectException
     */
    public function actionDelete()
    {
        $id = $this->post['id'];
        $user = Admin::findIdentity($id);
        if (empty($user)) {
            return $this->asFail('ID：【' . $id . '】错误数据不存在。');
        }
        if ($user->group == Admin::ADMIN_GROUP) {
            return $this->asFail('超级管理员账号禁止删除。');
        }

        $user->delete();
        return $this->asOk('删除管理员账号【'.$user->username.'】成功。');
    }

    /**
     * 查看管理员详情
     * @param int $id 管理员ID
     * @return string
     * @throws \Throwable
     */
    public function actionDetail($id)
    {
        $viewBuilder = $this->viewBuilder;
        $viewBuilder->setPartial();
        $user = Admin::findOneThrowEmptyException($id);/** @var Admin $user */
        $groupColumns = SystemGroup::query(['name'])->indexBy('id')->column();
        $groupColumns[Admin::ADMIN_GROUP] = function () {
            return '<i class="bi bi-people-fill f14 pr-1"></i>拥有者';
        };
        $viewBuilder->lists->setTitle('详情')
            ->setListLayout([
                'attribute' => ['lay-skin' => 'nob'],
            ])
            ->setListRows([
                '账号信息' => $this->listRows->item(function () use ($user) {
                    return MediaList::widget([
                        'media' => $user->photo,
                        'mediaBody' => [
                            '账号：' => $user->username,
                            '邮箱：' => $user->email ?: '-',
                            '手机：' => $user->mobile ?: '-',
                        ],
                    ]);
                })->thAttribute(['width' => 100]),
                '账号偏好' => $this->listRows->item(function () use ($user) {
                    $defaultViewTheme = $this->view->params;
                    if (empty($user->user_preference)) {
                        $viewTheme = $defaultViewTheme;
                    } else {
                        $userPreference = Json::decode($user->user_preference);
                        $viewTheme = $userPreference['view_theme'] ?? $defaultViewTheme;
                    }
                    return MediaList::widget([
                        'mediaList' => [
                            '菜单折叠：' => !empty($viewTheme['asideExpanded']) ? '展开' : '折叠',
                            '菜单布局：' => $viewTheme['menuLayout'] ?? $defaultViewTheme['menuLayout'],
                            '系统主题：' => ltrim(strrchr($viewTheme['uiTheme'] ?? $defaultViewTheme['uiTheme'], '-'), '-'),
                            '系统主色：' => function () use ($viewTheme, $defaultViewTheme) {
                                return H5::tag('div', '', [
                                    'style' => [
                                        'width' => '15px',
                                        'height' => '15px',
                                        'background-color' => $viewTheme['themeColor'] ?? $defaultViewTheme['themeColor'],
                                    ],
                                ]);
                            },
                        ],
                    ]);
                }),
                '管理组' => $this->listRows->item($groupColumns[$user->group]),
                '状态' => $this->listRows->item(function () use ($user) {
                    return H5::badge($user->status ? '正常' : '封停', $user->status ? 'success' : 'red');
                }),
                '封停截止' => $this->listRows->item($user->deny_end_time ?: '-'),
                '邀请码' => $this->listRows->item(function () use ($user) {
                    $result = [];
                    $result[] = Str::overflowMiddleEllipsis($user->invite_code, 15, '******');
                    $result[] = H5::duplicateButton($user->invite_code);
                    return implode("\n&emsp;", $result);
                }),
                'MFA Key' => $this->listRows->item(function () use ($user) {
                    return H5::imgX(
                        Extend::googleAuth()->getQRCodeGoogleUrl(App::params('admin.enBrandName'), $user->google_key, $user->username),
                        70,
                        70
                    );
                }),
                '注册时间' => $this->listRows->item($user->created_at),
                '上次更新' => $this->listRows->item($user->updated_at),
            ]);

        return $viewBuilder->render();
    }
}